package com.lemon.business;

import com.alibaba.fastjson.JSONObject;
import com.lemon.constant.Constant;
import com.lemon.entity.CpuDataVO;
import com.lemon.entity.DiskDataVO;
import com.lemon.entity.MachineVO;
import com.lemon.entity.MemoryDataVO;
import com.lemon.utils.JedisUtil;
import io.netty.buffer.ByteBuf;
import io.netty.channel.*;
import io.netty.handler.codec.http.*;
import io.netty.util.CharsetUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import redis.clients.jedis.JedisCluster;


import java.util.Map;

import static io.netty.buffer.Unpooled.copiedBuffer;

/**
 * @author lenomSeven 1337857379@qq.com
 * @date 2020/10/6
 */
public class EtlHandler extends SimpleChannelInboundHandler {
    private static final Logger logger = LoggerFactory.getLogger(EtlHandler.class);

    public void channelRead0(ChannelHandlerContext ctx, Object msg) {
        if (msg instanceof FullHttpRequest){
            try {
                FullHttpRequest fullHttpRequest = (FullHttpRequest) msg;
                if (!HttpMethod.POST.name().equals(fullHttpRequest.method().name())) { // 只接受pots访问
                    responseHandler(HttpResponseStatus.METHOD_NOT_ALLOWED, "Method Not Allowed", ctx);
                    logger.info("Method type error.");
                    return;
                }
                if (!Constant.UPLOAD_PATH.equals(fullHttpRequest.uri())) { //uri是否正确
                    responseHandler(HttpResponseStatus.NOT_FOUND, "Not Found", ctx);
                    logger.info("Path error.uri: {}", fullHttpRequest.uri());
                    return;
                }
                String token = fullHttpRequest.headers().get("Apm-token");
                if (!checkToken(token)) { // 检查token是否合法
                    responseHandler(HttpResponseStatus.FORBIDDEN, "Token Error", ctx);
                    logger.info("Token error.token: {}", token);
                    return;
                }
                // 防止重复上传 同一token 10秒内只能上传一次数据
                if (checkRepeat(token)) {
                    responseHandler(HttpResponseStatus.FORBIDDEN, "Data repeat upload.", ctx);
                    logger.info("Data repeat upload. token {}", token);
                    return;
                }
                String context = fullHttpRequest.content().toString(CharsetUtil.UTF_8);
                JSONObject obj = JSONObject.parseObject(context);
                cacheDataEntity(obj, token);
                responseHandler(HttpResponseStatus.OK, "Success", ctx);
            } catch (Exception e){
                responseHandler(HttpResponseStatus.INTERNAL_SERVER_ERROR, "Internal Server Error", ctx);
                logger.error("accept data error.", e);
            }
        }
    }

    /**
     * 检查数据是否重复上传
     * @return 真 重复  假 不重复
     **/
    private boolean checkRepeat(String token){
        JedisCluster jedis = JedisUtil.getJedisCluster();
        if (jedis.exists(Constant.CHECK_REPEAT_PREFIX + token)) { // 存在 则重复
            return true;
        } else { // 否则不重复
            jedis.setex(Constant.CHECK_REPEAT_PREFIX + token, 10, "lemon");
            return false;
        }
    }

    /**
     * 解析json 缓存到本地 等待入库
     * @param obj
     * @param token
     */
    private void cacheDataEntity(JSONObject obj, String token) {
        long dataTime = System.currentTimeMillis();
        Map<String, String> tokenMap = JedisUtil.getJedisCluster().hgetAll(token);
        String account = tokenMap.get(Constant.TOKEN_REDIS_KEY);
        String isUpdate = tokenMap.get(Constant.ISUPDATE_REDIS_KEY);
        if (!"0".equals(isUpdate)) { // 为0不用更新 非0更新
            MachineVO machineVO = new MachineVO();
            machineVO.setAccount(account);
            machineVO.setToken(token);
            if (obj.containsKey("memory")) {
                machineVO.setMemoryTotal(obj.getJSONObject("memory").getString("total"));
            }
            if (obj.containsKey("osName")) {
                machineVO.setOsName(obj.getString("osName"));
            }
            if (obj.containsKey("pcName")) {
                machineVO.setPcName(obj.getString("pcName"));
            }
            DataCache.getCache().addFirst(machineVO);
        }
        cacheCpu(obj, token, dataTime);
        cacheDisk(obj, token, dataTime);
        cacheMemory(obj, token, dataTime);
    }

    private void cacheCpu(JSONObject obj, String token, long dataTime){
        if (obj.containsKey("cpu")) {
            JSONObject data = obj.getJSONObject("cpu");
            for (Map.Entry<String, Object> entry : data.entrySet()) {
                CpuDataVO cpuDataVO = new CpuDataVO();
                cpuDataVO.setDataTime(dataTime);
                cpuDataVO.setToken(token);
                cpuDataVO.setCpuModel(entry.getKey());
                JSONObject cpuData = (JSONObject) entry.getValue();
                cpuDataVO.setAvgUsageRate(cpuData.getLong("avgUsageRate"));
                cpuDataVO.setLogicCoreNumber(cpuData.getLong("logicCoreNumber"));
                DataCache.getCache().addFirst(cpuDataVO);
            }
        }
    }

    private void cacheDisk(JSONObject obj, String token, long dataTime){
        if (obj.containsKey("disk")){
            JSONObject data = obj.getJSONObject("disk");
            for (Map.Entry<String, Object> entry : data.entrySet()) {
                DiskDataVO diskDataVO = new DiskDataVO();
                diskDataVO.setDataTime(dataTime);
                diskDataVO.setToken(token);
                diskDataVO.setDevName(entry.getKey());
                JSONObject diskData = (JSONObject) entry.getValue();
                diskDataVO.setTotal(diskData.getLong("total"));
                diskDataVO.setUse(diskData.getLong("use"));
                DataCache.getCache().addFirst(diskDataVO);
            }
        }
    }

    private void cacheMemory(JSONObject obj, String token, long dataTime){
        if (obj.containsKey("memory")){
            JSONObject data = obj.getJSONObject("memory");
            MemoryDataVO memoryDataVO = new MemoryDataVO();
            memoryDataVO.setDataTime(dataTime);
            memoryDataVO.setToken(token);
            memoryDataVO.setTotal(data.getLong("total"));
            memoryDataVO.setUse(data.getLong("use"));
            DataCache.getCache().addFirst(memoryDataVO);
        }
    }

    /**
     * 检查token
     * @param token 要检查的token
     * @return 真合法 假不合法
     */
    private boolean checkToken(String token){
        return JedisUtil.getJedisCluster().exists(token);
    }

    private void responseHandler(HttpResponseStatus status, String responseContent, ChannelHandlerContext ctx) {
        ByteBuf content = copiedBuffer(responseContent, CharsetUtil.UTF_8);
        FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, status, content);
        response.headers().set("Content-Type", "text/plain;charset=UTF-8;");
        response.headers().set("Content-Length", response.content().readableBytes());
        ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE);
    }
}